#!/bin/sh
# Shell script to play/record sound files to/from unix style sound devices.
# Should auto detect most supported systems.
#
# Originally developed by Chris Bagwell (cbagwell@sprynet.com)
#
#   TODO:  Put each set of fopts and filenames on an array and then 
#          play each filename back with the given effect. This
#          would allow the files to be of different data types
#          and sample rates.
#
# Change History:
#
#   Major updates have been supplied by Kjetil Torgrim Homme and 
#   Kirk Goff.

# Set up path so that it can find Sox if user's path doesn't already
# include it.
prefix=/usr/local
exec_prefix=${prefix}
bindir=${exec_prefix}/bin

HAVE_ALSA=0
HAVE_OSS=0
HAVE_SUNAU=0

# Look for sox in install directory first and then in current direction
# if not found.
PATH="$bindir:.:$PATH"

program_name=`basename $0`
rec_mode="no"
if [ "$program_name" = "rec" ]; then
    rec_mode="yes"
fi
program_version="3.0"

if [ -z "$1" ]; then
    echo "\
$program_name: too few arguments
Try \`$program_name --help' for more information." 1>&2
    exit 1
fi

version()
{
    echo "$program_name (sox) $program_version"
    exit 0
}

help()
{
    echo "\
Usage: $program_name [GENERAL OPTIONS] [FORMAT OPTIONS] FILE [EFFECT]...
Play/record sound files to/from unix style sound devices.

GENERAL OPTIONS:

General options should only be specified one.

  -d, --device=DEVICE          use DEVICE for input/output
  -V, --verbose                print verbose information
  -h, --help                   display this help and exit
      --version                output version information and exit

FORMAT OPTIONS:

File options can be specified for each filename.  Multiple filenames can
be specified when playing audio files but they must all be of
the data type and sample rates.

  -c, --channels=CHANNELS      specifies the number of sound channels in FILE
  -f, --format=FORMAT          specifies bit format of sample
                               FORMAT is either s, u, U, A, a, or g
  -r, --rate=RATE              sample rate in hertz of FILE
  -s, --size=SIZE              interpret size of sample
                               SIZE is either b, w, l, f, d, or D
  -t, --type=TYPE              specifies file format of FILE
  -v, --volume=VOLUME          change amplitude
  -x, --xinu                   reverse bit order of sample
                               (only works with 16-bit and 32-bit integer data)
      --file=FILENAME          specify filename

EFFECTs are one or more of the following:  avg, band, chorus, copy, cut, 
deemph, echo, echos, flanger, highp, lowp, map, mask, phaser, pick,
polyphase, rate, repeat, resample, reverb, reverse, split, stat, vibro.

See sox man page for detailed information on supported file types, data
formats, and effect options."
    exit 0
}

# loop over arguments
while [ $# -ne 0 ]; do
    case "$1" in
	avg|band|bandpass|bandreject|chorus|compand|copy|cut|deemph|earwax|echo|echos|fade|filter|flanger|highp|highpass|lowp|lowpass|map|mask|mcompand|noiseprof|noisered|pan|phaser|pick|pitch|polyphase|rate|repeat|resample|reverb|reverse|silence|speed|split|stat|stretch|swap|trim|vibro|vol)
	    effects="$@"
	    break
	    ;;
	-c)
	    shift
	    fopts="$fopts -c $1"
	    ;;
	--channels=*)
	    fopts="$fopts -c `echo $1 | sed 's/.*=//'`"
	    ;;
	-d)
	    shift
	    device="$1"
	    ;;
	--device=*)
	    device=`echo $1 | sed 's/.*=//'`
	    ;;
	-f)
	    shift
	    fopts="$fopts -$1"
	    ;;
	--format=*)
	    fopts="$fopts -`echo $1 | sed 's/.*=//'`"
	    ;;
	-r)
	    shift
	    fopts="$fopts -r $1"
	    ;;
	--rate=*)
	    fopts="$fopts -r `echo $1 | sed 's/.*=//'`"
	    ;;
	-s)
	    shift
	    fopts="$fopts -$1"
	    ;;
	--size=*)
	    fopts="$fopts -`echo $1 | sed 's/.*=//'`"
	    ;;
	-t)
	    shift
	    fopts2="$fopts -t $1"
	    ;;
	--type=*)
	    fopts2="$fopts -t `echo $1 | sed 's/.*=//'`"
	    ;;
	-v)
	    shift
	    fopts2="$fopts2 -v $1"
	    ;;
	--volume=*)
	    fopts2="$fopts2 -v `echo $1 | sed 's/.*=//'`"
	    ;;
        -V|--verbose)
            gopts="$gopts -V"
            ;;
	-x|--xinu)
	    fopts="$fopts -x"
	    ;;
	--file=*)
            if [ $rec_mode = "yes" ]; then
	        if [ -z "$filename" ]; then
                    filename=`echo $1 | sed 's/.*=//'`
                else
                    echo "Filename already given.  Ignoring extra name: $1" 1>&2
	        fi
            else
                filename=`echo $1 | sed 's/.*=//'`
                play_opts="$play_opts $fopts $fopts2 \"$filename\""
                fopts=""
                fopts2=""
            fi
	    ;;
	-h)
	    help
	    ;;
	--help)
	    help
	    ;;
	--version)
	    version
	    ;;
	-)
            if [ $rec_mode = "yes" ]; then
	        if [ -z "$filename" ]; then
	            filename="-"
                else
                    echo "Filename already given.  Ignoring extra name: $1" 1>&2
	        fi
            else
                filename="-"
                play_opts="$play_opts $fopts $fopts2 \"$filename\""
                fopts=""
                fopts2=""
            fi
	    ;;
	*)
            if [ $rec_mode = "yes" ]; then
	        if [ -z "$filename" ]; then
	            filename="$1"
                else
                    echo "Filename already given.  Ignoring extra name: $1" 1>&2
	        fi
            else
                filename=`echo $1 | sed 's/\ /\\\ /g'`
                filename=$1
                play_opts="$play_opts $fopts $fopts2 \"$filename\""
                fopts=""
                fopts2=""
            fi
	    ;;
    esac
    shift
done

# If user sets AUDIODEV environment variable then force output device
# to by that.  Solaris SunRay's make use of this for sure.
if [ -n "$AUDIODEV" ]; then
    device="$AUDIODEV"
fi

if [ "$HAVE_ALSA" = "1" ]; then
    arch_defines="-t alsa"
    if [ -z "$device" ]; then
	device="default"
    fi
else
    if [ "$HAVE_OSS" = "1" ]; then
        arch_defines="-t ossdsp"
        if [ -z "$device" ]; then
            device="/dev/dsp"
        fi
    else
        arch=`uname -s`
        case $arch in
            SunOS)
            case `uname -r` in
                # Solaris software can auto-detect hardware capabilities.
                5.*)
                arch_defines="-t sunau"
                ;;
                # For SunOS default to signed words.  Some hardware can only play u-law and would need
                # to be changed here.
                *)
                arch_defines="-t sunau -w -s"
                ;;
            esac
            if [ -z "$device" ]; then
                device="/dev/audio"
            fi
            ;;
            NetBSD|OpenBSD)
            arch_defines="-t sunau"
            if [ -z "$device" ]; then
                device="/dev/audio"
            fi
            ;;
        esac
    fi
fi

# If name is "rec" then record else assume user is wanting to play
# a sound file.
if [ "$rec_mode" = "yes" ]; then

    # Don't send data to stdout if they are reading from it.
    if [ "$filename" = "-" ]; then
      echo "Send break (control-c) to end recording" 1>&2
    else
      echo "Send break (control-c) to end recording"
    fi
    # $fopts are specified on both sides because audio driver
    # may not support the given format and might pick
    # something close to it.  Asume user really wants the
    # file to be in the specified format and so request
    # sox to do any conversions.
    sox $gopts $arch_defines $fopts $device $fopts $fopts2 "$filename" $effects 
else
    # Eval is needed to recongnize the quotes around filename
    # and let them be passed to program as 1 option (in case
    # filename has spaces).
    eval sox $gopts $play_opts $arch_defines $device $effects
fi
